import { HttpException, HttpStatus, Inject, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { Like, Repository } from 'typeorm';

import { EmailSerivce } from '@/email/email.service';
import { RedisService } from '@/redis/service/redis.service';

import { md5 } from '@/utils';

import { LoginUserDto } from './dtos/login.dto';
import { PaginteReturnDto, QueryUserDto } from './dtos/queryUser.dto';
import { RegisterUserDto, UpdatePasswordDto } from './dtos/register.dto';
import { CaptchaCode } from './types';
import { UpdateUserDto } from './dtos/updateUser.dto';
import { PermissionEntity, RoleEntity, UserEntity } from './entities';

import { LoginUserVo } from './vo/login-user.vo';

@Injectable()
export class UserService {
    private logger = new Logger();

    @InjectRepository(UserEntity)
    private repository: Repository<UserEntity>;

    @InjectRepository(RoleEntity)
    private roleRepository: Repository<RoleEntity>;

    @InjectRepository(PermissionEntity)
    private permissionRepository: Repository<PermissionEntity>;

    @Inject(RedisService)
    private redisService: RedisService;

    @Inject(EmailSerivce)
    private emailService: EmailSerivce;

    @Inject(ConfigService)
    protected configService: ConfigService;

    @Inject(JwtService)
    protected jwtService: JwtService;

    // 初始化数据
    async initData() {
        const user1 = new UserEntity();
        user1.username = 'zhangsan';
        user1.password = md5('111111');
        user1.nickname = '张三';
        user1.isAdmin = true;
        user1.email = 'xxx@xx.com';
        user1.phoneNumber = '13833148108';

        const user2 = new UserEntity();
        user2.username = 'lisi';
        user2.password = md5('222222');
        user2.nickname = '李四';
        user2.email = 'xxx@xx.com';
        user2.phoneNumber = '13833148108';

        const role1 = new RoleEntity();
        role1.name = '管理员';

        const role2 = new RoleEntity();
        role2.name = '普通用户';

        const permission1 = new PermissionEntity();
        permission1.code = 'ccc';
        permission1.description = '访问ccc接口';

        const permission2 = new PermissionEntity();
        permission2.code = 'ddd';
        permission2.description = '访问ddd接口';

        user1.roles = [role1];
        user2.roles = [role2];

        role1.permissions = [permission1, permission2];
        role2.permissions = [permission1];

        await this.permissionRepository.save([permission1, permission2]);
        await this.roleRepository.save([role1, role2]);
        await this.repository.save([user1, user2]);
    }

    async register(user: RegisterUserDto) {
        const captcha = await this.redisService.get(`captcha_${user.email}`);
        if (!captcha) {
            throw new HttpException('验证码已失效', HttpStatus.BAD_REQUEST);
        }
        if (captcha !== user.captcha) {
            throw new HttpException('验证码错误', HttpStatus.BAD_REQUEST);
        }
        const foundUser = await this.repository.findOneBy({
            username: user.username,
        });
        if (foundUser) {
            throw new HttpException('该用户已存在', HttpStatus.BAD_REQUEST);
        }
        user.password = md5(user.password);
        try {
            await this.repository.save(user);
            return '注册成功';
        } catch (e) {
            this.logger.error(e, UserService);
            return '注册失败';
        }
    }

    // 根据id查询单条数据
    async findUserById(userId: number, isAdmin: boolean) {
        const user = await this.repository.findOne({
            where: {
                id: userId,
                isAdmin,
            },
            relations: ['roles', 'roles.permissions'],
        });

        return {
            id: user.id,
            username: user.username,
            isAdmin: user.isAdmin,
            roles: user.roles.map((item) => item.name),
            permissions: user.roles.reduce((arr, item) => {
                item.permissions.forEach((permission) => {
                    if (arr.indexOf(permission) === 1) {
                        arr.push(permission);
                    }
                });
                return arr;
            }, []),
        };
    }

    async findUserDetailById(userId: number) {
        const user = await this.repository.findOne({
            where: {
                id: userId,
            },
        });
        return user;
    }

    // 用户登录
    async login(loginUser: LoginUserDto, isAdmin: boolean) {
        const user = await this.repository.findOne({
            where: {
                username: loginUser.username,
                isAdmin,
            },
            relations: ['roles', 'roles.permissions'],
        });
        if (!user) {
            throw new HttpException('此用户不存在', HttpStatus.BAD_REQUEST);
        }
        if (user.password !== md5(loginUser.password)) {
            throw new HttpException('密码错误', HttpStatus.BAD_REQUEST);
        }
        const vo = new LoginUserVo();
        vo.userInfo = {
            id: user.id,
            username: user.username,
            nickname: user.nickname,
            email: user.email,
            phoneNumber: user.phoneNumber,
            headPic: user.headPic,
            createTime: user.createTime.getTime(),
            isFrozen: user.isFrozen,
            isAdmin: user.isAdmin,
            roles: user.roles.map((item) => item.name),
            permissions: user.roles.reduce((arr, item) => {
                item.permissions.forEach((perm) => {
                    if (arr.indexOf(perm) === -1) {
                        arr.push(perm);
                    }
                });
                return arr;
            }, []),
        };

        return vo;
    }

    // 发送验证码
    async sendCode(codeData: CaptchaCode) {
        await this.redisService.set(`${codeData.prefix + codeData.address}`, codeData.code, 5 * 60);

        await this.emailService.sendMail({
            to: codeData.address,
            subject: codeData.subject,
            html: codeData.html,
        });
        return '发送成功';
    }

    // 生成accesstoken和refreshtoken
    jwtData(vo: LoginUserVo) {
        vo.accessToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
                username: vo.userInfo.username,
                roles: vo.userInfo.roles,
                permissions: vo.userInfo.permissions,
            },
            {
                expiresIn: this.configService.get('jwt_access_token_expires_time') || '30m',
            },
        );
        vo.refreshToken = this.jwtService.sign(
            {
                userId: vo.userInfo.id,
            },
            {
                expiresIn: this.configService.get('jwt_refresh_token_expires_time') || '7d',
            },
        );
        console.log(vo);
        return vo;
    }

    // 更新密码
    async updatePassword(userId: number, passwordDto: UpdatePasswordDto) {
        const captcha = await this.redisService.get(`update_password_captcha_${passwordDto.email}`);
        if (!captcha) {
            throw new HttpException('验证码已失效', HttpStatus.BAD_REQUEST);
        }
        if (captcha !== passwordDto.captcha) {
            throw new HttpException('验证码不正确', HttpStatus.BAD_REQUEST);
        }

        const user = await this.repository.findOneBy({
            id: userId,
        });
        console.log(user);
        user.password = md5(passwordDto.password);
        user.email = passwordDto.email;
        try {
            await this.repository.save(user);
            return '修改成功';
        } catch (e) {
            this.logger.error(e, UserService);
            return '修改失败';
        }
    }

    // 更新用户信息
    async update(userId: number, updateUserDto: UpdateUserDto) {
        const user = await this.repository.findOneBy({
            id: userId,
        });

        const newUser = {
            ...user,
            ...updateUserDto,
        };
        try {
            await this.repository.save(newUser);
            return '用户信息修改成功';
        } catch (e) {
            this.logger.error(e, UserService);
            return '用户信息修改失败';
        }
    }

    // 冻结用户
    async freezeUserById(id: number) {
        const user = await this.repository.findOneBy({
            id,
        });

        user.isFrozen = true;

        await this.repository.save(user);
    }

    // 查询列表
    async findUsersByPage(options: QueryUserDto) {
        const { page, pageSize, username, nickname, email } = options;
        console.log(options);
        const condition: Record<string, any> = {};
        if (username) {
            condition.username = Like(`%${username}%`);
        }
        if (nickname) {
            condition.nickname = Like(`%${nickname}%`);
        }

        if (email) {
            condition.email = Like(`%${email}%`);
        }

        const skipCount = (page - 1) * pageSize;

        const [users, totalCount] = await this.repository.findAndCount({
            select: [
                'id',
                'username',
                'nickname',
                'email',
                'phoneNumber',
                'isFrozen',
                'headPic',
                'createTime',
            ],
            skip: skipCount,
            take: pageSize,
            where: condition,
        });
        return {
            users,
            totalCount,
        };
    }
}
